package data

import (
	"blog/model"
	"fmt"
	"html"
	"html/template"
	"math"
	"strings"
	"time"

	"gitee.com/xchengli/blog-lib/database"
	"gitee.com/xchengli/blog-lib/zlog"

	"github.com/gin-gonic/gin"
)

type PostDataService struct{}

// PostDataReal 文章数据（原始版本）
type PostDataReal struct {
	ID           int    `json:"id"`
	Author       int    `json:"author"`
	PostType     int    `json:"post_type"`
	Title        string `json:"title"`
	Content      string `json:"content"`
	ReadNum      int    `json:"read_num"`
	IsPrivate    uint   `json:"is_private"`
	IsShow       uint   `json:"is_show"`
	IsRemark     uint   `json:"is_remark"`
	IsTemp       uint   `json:"is_temp"`
	IsStar       uint   `json:"is_star"`
	CreateTime   string `json:"add_time"`
	LastEditTime string `json:"last_edit_time"`
}

// PostData 文章数据（完整版本）
type PostData struct {
	PostDataReal
	PostTypeHtml template.HTML   `json:"post_type_info"`
	TitleHtml    template.HTML   `json:"title"`
	ContentHtml  template.HTML   `json:"content"`
	FmtShowTime  template.HTML   `json:"fmt_show_time"`
	Tags         []model.TagData `json:"tags"`
}

// GetPostList 获取文章列表数据
func (s *PostDataService) GetPostList(ctx *gin.Context, page, pageSize int) ([]model.Post, int64, error) {
	var posts []model.Post
	var total int64

	db := database.GetDB()

	// 获取总数
	if err := db.Model(&model.Post{}).Where("is_show = ?", 1).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (page - 1) * pageSize
	if err := db.Where("is_show = ? AND is_private = ? AND is_temp = ?", 1, 0, 0).
		Order("add_time DESC").
		Offset(offset).Limit(pageSize).
		Find(&posts).Error; err != nil {
		return nil, 0, err
	}

	return posts, total, nil
}

// GetPostByID 根据ID获取文章
func (s *PostDataService) GetPostByID(ctx *gin.Context, id int64) (*model.Post, error) {
	var post model.Post
	db := database.GetDB()

	if err := db.Where("id = ? AND is_show = ?", id, 1).First(&post).Error; err != nil {
		return nil, err
	}

	return &post, nil
}

// GetPostRealByID 根据ID获取文章（PostDataReal版本）
func (s *PostDataService) GetPostRealByID(ctx *gin.Context, id int64) (*PostDataReal, error) {
	var post PostDataReal
	db := database.GetDB()

	if err := db.Table("bg_posts").Where("id = ?", id).First(&post).Error; err != nil {
		return nil, err
	}

	return &post, nil
}

// GetNewPosts 获取最新文章
func (s *PostDataService) GetNewPosts(ctx *gin.Context, limit int) ([]model.NewPostList, error) {
	var posts []model.NewPostList
	db := database.GetDB()

	if err := db.Table("bg_posts").
		Select("id, title").
		Where("is_show = ? AND is_private = ? AND is_temp = ?", 1, 0, 0).
		Order("add_time DESC").
		Limit(limit).
		Find(&posts).Error; err != nil {
		return nil, err
	}

	return posts, nil
}

// SearchPosts 搜索文章
func (s *PostDataService) SearchPosts(ctx *gin.Context, keyword string, page, pageSize int) ([]model.Post, int64, error) {
	var posts []model.Post
	var total int64

	db := database.GetDB()

	// 获取总数
	if err := db.Model(&model.Post{}).
		Where("is_show = ? AND is_private = ? AND is_temp = ? AND (title LIKE ? OR content LIKE ?)",
			1, 0, 0, "%"+keyword+"%", "%"+keyword+"%").
		Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取分页数据
	offset := (page - 1) * pageSize
	if err := db.Where("is_show = ? AND is_private = ? AND is_temp = ? AND (title LIKE ? OR content LIKE ?)",
		1, 0, 0, "%"+keyword+"%", "%"+keyword+"%").
		Order("add_time DESC").
		Offset(offset).Limit(pageSize).
		Find(&posts).Error; err != nil {
		return nil, 0, err
	}

	return posts, total, nil
}

// CreatePost 创建文章
func (s *PostDataService) CreatePost(ctx *gin.Context, post *model.Post) error {
	db := database.GetDB()
	return db.Create(post).Error
}

// CreatePostReal 创建文章（PostDataReal版本）
func (s *PostDataService) CreatePostReal(ctx *gin.Context, post *PostDataReal) error {
	db := database.GetDB()
	return db.Table("bg_posts").Create(post).Error
}

// UpdatePost 更新文章
func (s *PostDataService) UpdatePost(ctx *gin.Context, post *model.Post) error {
	db := database.GetDB()
	return db.Save(post).Error
}

// UpdatePostReal 更新文章（PostDataReal版本）
func (s *PostDataService) UpdatePostReal(ctx *gin.Context, post *PostDataReal) error {
	db := database.GetDB()
	post.LastEditTime = time.Now().Format("2006-01-02 15:04:05")
	return db.Table("bg_posts").Save(post).Error
}

// DeletePost 删除文章
func (s *PostDataService) DeletePost(ctx *gin.Context, id int64) error {
	db := database.GetDB()
	return db.Model(&model.Post{}).Where("id = ?", id).Update("is_show", 0).Error
}

// IncrementReadCount 增加阅读量
func (s *PostDataService) IncrementReadCount(ctx *gin.Context, id int64) error {
	db := database.GetDB()
	return db.Model(&model.Post{}).Where("id = ?", id).UpdateColumn("read_num", db.Raw("read_num + 1")).Error
}

// GetPostInfo 获取文章信息
func (s *PostDataService) GetPostInfo(ctx *gin.Context, id int64, isByAdmin bool) (PostData, error) {
	var info PostData
	db := database.GetDB()

	var title, content string
	err := db.Table("bg_posts").
		Select("id, author, post_type, title, content, read_num, add_time, is_private, is_show, is_remark, is_temp, is_star, last_edit_time").
		Where("id = ?", id).
		Row().Scan(&info.ID, &info.Author, &info.PostType, &title, &content, &info.ReadNum, &info.CreateTime, &info.IsPrivate, &info.IsShow, &info.IsRemark, &info.IsTemp, &info.IsStar, &info.LastEditTime)

	if err != nil {
		return info, err
	}

	info.TitleHtml = template.HTML(html.UnescapeString(title))
	info.ContentHtml = template.HTML(html.UnescapeString(content))
	info.FmtShowTime = template.HTML(info.CreateTime[:16])

	// 获取标签
	tagService := &TagDataService{}
	info.Tags = tagService.GetPostTags(ctx, int(info.ID))

	// 获取分类信息
	typeService := &TypeDataService{}
	postTypeInfo := typeService.GetPostTypeInfo(ctx, info.PostType)
	info.PostTypeHtml = typeService.ToHtml(postTypeInfo, isByAdmin)

	return info, nil
}

// GetPostListForIndex 获取首页文章列表
func (s *PostDataService) GetPostListForIndex(ctx *gin.Context, page, limitNum, types int64, isByAdmin bool) model.PostListData {
	lists := model.PostListData{}
	if limitNum <= 0 {
		return lists
	}

	lists.CurrentPage = int(page)
	lists.DataNum = 0
	lists.PageNum = 0
	lists.PageSize = int(limitNum)
	lists.Lists = make(map[int64]model.PostDataSimple)

	db := database.GetDB()

	// 构建查询条件
	var whereConditions []string
	var args []interface{}

	if types != 0 {
		typeService := &TypeDataService{}
		ids := typeService.GetSonIds(ctx, int(types))
		if len(ids) < 1 {
			whereConditions = append(whereConditions, "post_type = ?")
			args = append(args, types)
		} else {
			placeholders := make([]string, len(ids))
			for i := range ids {
				placeholders[i] = "?"
				args = append(args, ids[i])
			}
			whereConditions = append(whereConditions, fmt.Sprintf("post_type IN (%s)", strings.Join(placeholders, ",")))
		}
	}

	whereConditions = append(whereConditions, "is_show = 1 AND is_private = 0 AND is_temp = 0")
	whereClause := strings.Join(whereConditions, " AND ")

	// 获取总数
	var total int64
	err := db.Table("bg_posts").Where(whereClause, args...).Count(&total).Error
	if err != nil {
		zlog.ErrorW(ctx, "获取文章总数失败", "err", err.Error())
		return lists
	}
	lists.DataNum = int(total)

	if lists.DataNum == 0 {
		return lists
	}

	lists.PageNum = int(math.Ceil(float64(lists.DataNum) / float64(limitNum)))

	// 获取分页数据
	offset := (page - 1) * limitNum
	args = append(args, offset, limitNum)

	rows, err := db.Table("bg_posts").
		Select("id, author, post_type, title, content, read_num, add_time, is_remark, is_star, last_edit_time, is_private, is_show, is_temp").
		Where(whereClause).
		Order("add_time DESC").
		Limit(int(limitNum)).Offset(int(offset)).
		Rows()

	if err != nil {
		zlog.ErrorW(ctx, "获取文章列表失败", "err", err.Error())
		return lists
	}
	defer rows.Close()

	var m int64 = 0
	for rows.Next() {
		var d PostData
		d.IsPrivate = 0
		d.IsTemp = 0
		d.IsShow = 1

		var title, content string
		err := rows.Scan(&d.ID, &d.Author, &d.PostType, &title, &content, &d.ReadNum, &d.CreateTime, &d.IsRemark, &d.IsStar, &d.LastEditTime, &d.IsPrivate, &d.IsShow, &d.IsTemp)
		if err != nil {
			zlog.ErrorW(ctx, "扫描文章数据失败", "err", err.Error())
			continue
		}

		d.TitleHtml = template.HTML(html.UnescapeString(title))
		d.ContentHtml = template.HTML(html.UnescapeString(content))

		// 获取标签
		tagService := &TagDataService{}
		d.Tags = tagService.GetPostTags(ctx, d.ID)

		// 获取分类信息
		typeService := &TypeDataService{}
		postTypeInfo := typeService.GetPostTypeInfo(ctx, d.PostType)
		d.PostTypeHtml = typeService.ToHtml(postTypeInfo, isByAdmin)
		d.FmtShowTime = template.HTML(d.CreateTime[:16])

		// 转换为简化版数据
		lists.Lists[m] = model.PostDataSimple{
			ID:         int64(d.ID),
			Title:      d.Title,
			Content:    d.Content,
			TypeID:     d.PostType,
			TypeName:   postTypeInfo.Name,
			IsTemp:     int(d.IsTemp),
			IsShow:     int(d.IsShow),
			IsPrivate:  int(d.IsPrivate),
			Tags:       s.tagDataToStrings(d.Tags),
			ReadCount:  d.ReadNum,
			CreateTime: s.parseTime(d.CreateTime),
		}
		m++
	}

	return lists
}

// GetPostListByKeyword 根据关键词获取文章列表
func (s *PostDataService) GetPostListByKeyword(ctx *gin.Context, keyWord, tagName string, typeId, page, limitNum int64, byAdmin bool) model.PostListData {
	lists := model.PostListData{}
	if limitNum <= 0 {
		return lists
	}

	lists.CurrentPage = int(page)
	lists.DataNum = 0
	lists.PageNum = 0
	lists.PageSize = int(limitNum)
	lists.Lists = make(map[int64]model.PostDataSimple)

	db := database.GetDB()

	var whereConditions []string
	var args []interface{}

	if typeId != 0 {
		typeService := &TypeDataService{}
		ids := typeService.GetSonIds(ctx, int(typeId))
		if len(ids) < 1 {
			whereConditions = append(whereConditions, "post_type = ?")
			args = append(args, typeId)
		} else {
			placeholders := make([]string, len(ids))
			for i, id := range ids {
				placeholders[i] = "?"
				args = append(args, id)
			}
			whereConditions = append(whereConditions, fmt.Sprintf("post_type IN (%s)", strings.Join(placeholders, ",")))
		}
	}

	if keyWord != "" {
		whereConditions = append(whereConditions, "(title LIKE ? OR content LIKE ?)")
		args = append(args, "%"+keyWord+"%", "%"+keyWord+"%")
	}

	if tagName != "" {
		tagService := &TagDataService{}
		ids := tagService.GetPostIdsByTagName(ctx, tagName)
		if len(ids) < 1 {
			return lists
		} else {
			placeholders := make([]string, len(ids))
			for i, id := range ids {
				placeholders[i] = "?"
				args = append(args, id)
			}
			whereConditions = append(whereConditions, fmt.Sprintf("id IN (%s)", strings.Join(placeholders, ",")))
		}
	}

	// 是否前台调用
	if !byAdmin {
		whereConditions = append(whereConditions, "is_show = 1 AND is_private = 0 AND is_temp = 0")
	}

	whereConditions = append(whereConditions, "1")
	whereClause := strings.Join(whereConditions, " AND ")

	// 获取总数
	var total int64
	err := db.Table("bg_posts").Where(whereClause, args...).Count(&total).Error
	if err != nil {
		zlog.ErrorW(ctx, "获取文章总数失败", "err", err.Error())
		return lists
	}
	lists.DataNum = int(total)

	if lists.DataNum == 0 {
		return lists
	}

	lists.PageNum = int(math.Ceil(float64(lists.DataNum) / float64(limitNum)))

	// 获取分页数据
	offset := (page - 1) * limitNum
	args = append(args, offset, limitNum)

	rows, err := db.Table("bg_posts").
		Select("id, author, post_type, title, content, read_num, add_time, is_remark, is_star, last_edit_time, is_private, is_show, is_temp").
		Where(whereClause).
		Order("add_time DESC, id DESC").
		Limit(int(limitNum)).Offset(int(offset)).
		Rows()

	if err != nil {
		zlog.ErrorW(ctx, "获取文章列表失败", "err", err.Error())
		return lists
	}
	defer rows.Close()

	var m int64 = 0
	for rows.Next() {
		var d PostData
		d.IsPrivate = 0
		d.IsTemp = 0
		d.IsShow = 1

		var title, content string
		err := rows.Scan(&d.ID, &d.Author, &d.PostType, &title, &content, &d.ReadNum, &d.CreateTime, &d.IsRemark, &d.IsStar, &d.LastEditTime, &d.IsPrivate, &d.IsShow, &d.IsTemp)
		if err != nil {
			zlog.ErrorW(ctx, "扫描文章数据失败", "err", err.Error())
			continue
		}

		d.TitleHtml = template.HTML(html.UnescapeString(title))
		d.ContentHtml = template.HTML(html.UnescapeString(content))

		// 获取标签
		tagService := &TagDataService{}
		d.Tags = tagService.GetPostTags(ctx, d.ID)

		// 获取分类信息
		typeService := &TypeDataService{}
		postTypeInfo := typeService.GetPostTypeInfo(ctx, d.PostType)
		d.PostTypeHtml = typeService.ToHtml(postTypeInfo, byAdmin)
		d.FmtShowTime = template.HTML(d.CreateTime[:16])

		if d.LastEditTime == "1970-01-01 00:00:00" {
			d.LastEditTime = ""
		}

		// 转换为简化版数据
		lists.Lists[m] = model.PostDataSimple{
			ID:         int64(d.ID),
			Title:      d.Title,
			Content:    d.Content,
			TypeID:     d.PostType,
			TypeName:   postTypeInfo.Name,
			IsTemp:     int(d.IsTemp),
			IsShow:     int(d.IsShow),
			IsPrivate:  int(d.IsPrivate),
			Tags:       s.tagDataToStrings(d.Tags),
			ReadCount:  d.ReadNum,
			CreateTime: s.parseTime(d.CreateTime),
		}
		m++
	}

	return lists
}

// CheckAddPostTypeId 检查文章分类ID是否有效
func (s *PostDataService) CheckAddPostTypeId(ctx *gin.Context, id int64) bool {
	db := database.GetDB()
	var count int64
	err := db.Table("bg_posts_type").Where("id = ? AND fid <> 0", id).Count(&count).Error
	if err != nil {
		return false
	}
	return count >= 1
}

// CheckPostTitle 检查文章标题是否合法
func (s *PostDataService) CheckPostTitle(title string) (bool, string) {
	if len(title) < 4 {
		return false, "标题文字不得少于4个字符"
	}

	if len(title) > 24 {
		return false, "标题文字不得多于24个字符"
	}

	return true, ""
}

// CheckPostContent 检查文章内容是否合法
func (s *PostDataService) CheckPostContent(content string) (bool, string) {
	if len(content) < 6 {
		return false, "内容文字不得少于6个字符"
	}

	if len(content) > 1024*1024 {
		return false, "内容太长"
	}

	return true, ""
}

// GetPostNum 获取分类的文章数
func (s *PostDataService) GetPostNum(ctx *gin.Context, postType, isShow int) int {
	var whereConditions []string
	var args []interface{}

	if isShow == 1 {
		whereConditions = append(whereConditions, "is_show = 1")
	} else if isShow == 0 {
		whereConditions = append(whereConditions, "is_show = 0")
	}

	typeService := &TypeDataService{}
	sonIds := typeService.GetSonIds(ctx, postType)
	if len(sonIds) >= 1 {
		placeholders := make([]string, len(sonIds)+1)
		placeholders[0] = "?"
		args = append(args, postType)
		for i, v := range sonIds {
			placeholders[i+1] = "?"
			args = append(args, v)
		}
		whereConditions = append(whereConditions, fmt.Sprintf("post_type IN (%s)", strings.Join(placeholders, ",")))
	} else {
		whereConditions = append(whereConditions, "post_type = ?")
		args = append(args, postType)
	}

	db := database.GetDB()
	var num int64
	whereClause := strings.Join(whereConditions, " AND ")

	err := db.Table("bg_posts").Where(whereClause, args...).Count(&num).Error
	if err != nil {
		zlog.ErrorW(ctx, "获取文章数量失败", "err", err.Error())
		return 0
	}

	return int(num)
}

// tagDataToStrings 将标签数据转换为字符串数组
func (s *PostDataService) tagDataToStrings(tags []model.TagData) []string {
	var result []string
	for _, t := range tags {
		result = append(result, t.Name)
	}
	return result
}

// parseTime 解析时间字符串
func (s *PostDataService) parseTime(timeStr string) time.Time {
	t, _ := time.Parse("2006-01-02 15:04:05", timeStr)
	if t.IsZero() {
		return time.Now()
	}
	return t
}
